{plotly} is an open source graphing library
plotly is a high-level interface to plotly.js, based on d3.js which provides an easy-to-use UI to
generate slick D3 interactive graphics.
Plot work in multiple formats: viewer windows, R Markdown documents, shiny apps
plotly is also backed by a strong community and active development
plotly works with R, python, excel, and others. We will just focus on R in this class.
library(plyr) # https://cran.r-project.org/web/packages/plyr/index.html
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.2 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ ggplot2 3.4.3 ✔ tibble 3.2.1
## ✔ lubridate 1.9.2 ✔ tidyr 1.3.0
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::arrange() masks plyr::arrange()
## ✖ purrr::compact() masks plyr::compact()
## ✖ dplyr::count() masks plyr::count()
## ✖ dplyr::desc() masks plyr::desc()
## ✖ dplyr::failwith() masks plyr::failwith()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::id() masks plyr::id()
## ✖ dplyr::lag() masks stats::lag()
## ✖ dplyr::mutate() masks plyr::mutate()
## ✖ dplyr::rename() masks plyr::rename()
## ✖ dplyr::summarise() masks plyr::summarise()
## ✖ dplyr::summarize() masks plyr::summarize()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(plotly) # (https://plotly.com/)
##
## Attaching package: 'plotly'
##
## The following object is masked from 'package:ggplot2':
##
## last_plot
##
## The following objects are masked from 'package:plyr':
##
## arrange, mutate, rename, summarise
##
## The following object is masked from 'package:stats':
##
## filter
##
## The following object is masked from 'package:graphics':
##
## layout
# read in 'wine.csv' data
wine <- read.csv('wine.csv')
head(wine)
## Type Alcohol Malic Ash Alcalinity Magnesium Phenols Flavanoids Nonflavanoids
## 1 1 14.23 1.71 2.43 15.6 127 2.80 3.06 0.28
## 2 1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26
## 3 1 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30
## 4 1 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24
## 5 1 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39
## 6 1 14.20 1.76 2.45 15.2 112 3.27 3.39 0.34
## Proanthocyanins Color Hue Dilution Proline
## 1 2.29 5.64 1.04 3.92 1065
## 2 1.28 4.38 1.05 3.40 1050
## 3 2.81 5.68 1.03 3.17 1185
## 4 2.18 7.80 0.86 3.45 1480
## 5 1.82 4.32 1.04 2.93 735
## 6 1.97 6.75 1.05 2.85 1450
wine$Type <- as.factor(wine$Type)
ggplotlyLet’s look at a static graph comparing flavanoids to
proline
static_plot <- wine %>%
ggplot(aes(x = Flavanoids, y = Proline, color = Type)) +
geom_point() +
theme_minimal() +
scale_color_manual(values = c("#00AFBB", "#E7B800", "#FC4E07"))
static_plot
There are two main approaches to initialize a plotly object:
ggplotly()plot_ly() directly
ggplotly()ggplotly() takes existing ggplot2
objects and converts them into interactive plotly graphics.
That is, ggplotly() converts your static plots to an
interactive web-based version!
This makes it easy to create interactive figures because we are
already familiar to the ggplot2 syntax.
# Create an interactive plot of Flavonoids vs Proline
ggplotly(static_plot)
Downloading the plot as a png file. Zoom Panning across the map. Selecting all points using a box. Selecting all points using a lasso. Zooming in and out on our plots. Resetting the view. data
Interactive plots are great!
Bad Design = Bad Interactive Plots
Follow data-viz best practices
g <- ggplot(data = wine, aes(x = Type, fill = Type)) +
geom_bar(fill = c("#00AFBB", "#E7B800", "#FC4E07")) +
theme_classic()
ggplotly(g)
g.5 <- count(wine, Type) %>%
ggplot(aes(x = reorder(Type, -n), y = n)) +
geom_bar(fill = c("#00AFBB", "#E7B800", "#FC4E07"), stat = 'identity') +
theme_classic() +
xlab('Type')
ggplotly(g.5)
g2 <- ggplot(wine, aes(x = Flavanoids, fill = as.factor(Type))) +
geom_histogram(bins = 15, alpha = 0.6) +
theme_minimal()
scale_fill_manual(values = c("#00AFBB", "#E7B800", "#FC4E07"))
## <ggproto object: Class ScaleDiscrete, Scale, gg>
## aesthetics: fill
## axis_order: function
## break_info: function
## break_positions: function
## breaks: waiver
## call: call
## clone: function
## dimension: function
## drop: TRUE
## expand: waiver
## get_breaks: function
## get_breaks_minor: function
## get_labels: function
## get_limits: function
## guide: legend
## is_discrete: function
## is_empty: function
## labels: waiver
## limits: NULL
## make_sec_title: function
## make_title: function
## map: function
## map_df: function
## n.breaks.cache: NULL
## na.translate: TRUE
## na.value: grey50
## name: waiver
## palette: function
## palette.cache: NULL
## position: left
## range: environment
## rescale: function
## reset: function
## scale_name: manual
## train: function
## train_df: function
## transform: function
## transform_df: function
## super: <ggproto object: Class ScaleDiscrete, Scale, gg>
ggplotly(g2)
g4 <- ggplot(wine, aes(x = Flavanoids, y = Proline, color = as.factor(Type))) +
geom_point() +
geom_smooth(method="loess", formula=y~x, se=F) +
scale_color_manual(values = c("#00AFBB", "#E7B800", "#FC4E07"), name = 'Type') +
theme_bw()
ggplotly(g4)
# Flavonoids are rich in antioxidant
# A large percentage of the total amino acid left in the wine is in the form of proline
plot_lyplot_ly() is the base plotly command to
initialize a plot from a dataframe, similar to ggplot()
from ggplot2.plotlylibrary(plotly)
wine %>%
count(Type) %>% #using dplyr create frequency table
plot_ly(x = ~Type, y = ~n) %>% # initialize graph in plotly, use ~ for aes mappings
add_bars() %>% #set graph as bar chart
layout(title = "Freq. of Wine Soil Type",
xaxis = list(title = "Type"),
yaxis = list(title = "Frequency"))
wine %>%
count(Type) %>% #using dplyr create frequency table
mutate(Type = fct_reorder(Type, n, .desc = TRUE)) %>% #order for largest to smallest
plot_ly(x = ~Type, y = ~n) %>% # initialize graph in plotly, use ~ for aes mappings
add_bars() %>% #set graph as bar chart
layout(title = "Freq. of Wine Soil Type",
xaxis = list(title = "Type"),
yaxis = list(title = "Frequency"))
g6 <- wine %>% plot_ly(x = ~ Flavanoids, type = "histogram")
g6
# Lets split up the data to illustrate the manual way of making the plots
Type1 <- wine %>% filter(Type == 1)
Type2 <- wine %>% filter(Type == 2)
Type3 <- wine %>% filter(Type == 3)
# Full Manual method without for loop, subsetting data before
g7a <- plot_ly(alpha = 0.4) %>%
add_histogram(x = ~Type1$Flavanoids, name = 'Type 1', opacity = 0.6,
marker = list(color = "#00AFBB",
alpha = 0.6,
line = list(color = "lightgray",
width = 2))) %>%
add_histogram(x = ~Type2$Flavanoids, name = 'Type 2', opacity = 0.6,
marker = list(color = "#E7B800",
line = list(color = "lightgray",
width = 2))) %>%
add_histogram(x = ~Type3$Flavanoids, name = 'Type 3', opacity = 0.6,
marker = list(color = "#FC4E07",
line = list(color = "lightgray",
width = 2))) %>%
layout(barmode = 'overlay',
title = 'Histogram of flavanoids by soil type',
xaxis = list(title = 'flavanoids',
zeroline = FALSE),
yaxis = list(title = 'count'))
g7a
# Manual method with for-loop that temp subsets data by soil type on the fly
my_colors <- c("#00AFBB","#E7B800","#FC4E07")
g7b <- wine %>%
plot_ly() # initialize graph in plotly, use ~ for aes mappings
for (n in 1:(length(levels(wine$Type)))) {
temp <- subset(wine, Type == levels(wine$Type)[n])
g7b <- add_histogram(g7b, data = temp, x = ~Flavanoids, name = paste0("Type ", n),
opacity = 0.6, marker = list(color = my_colors[n], line = list(color = "lightgray",
width = 2)))
}
g7b <- g7b %>% layout(barmode = 'overlay',
title = 'Histogram of flavanoids by soil type',
xaxis = list(title = 'flavanoids',
zeroline = FALSE),
yaxis = list(title = 'count'))
g7b
# Automated method, ggplot style
g7c <- wine %>%
# initialize graph in plotly, use ~ for aes mappings
plot_ly(x = ~Flavanoids, color = ~Type, colors = c("#00AFBB","#E7B800","#FC4E07")) %>%
add_histogram(opacity = 0.6, marker = list(line = list(color = "lightgray", width = 2))) %>%
layout(barmode = 'overlay',
title = 'Histogram of flavanoids by soil type',
xaxis = list(title = 'flavanoids',
zeroline = FALSE),
yaxis = list(title = 'count'))
g7c
# Manual subset method with more control for formatting
# Using dataframe subsets Type1, Type2, Type3 we generated earlier
g8a <- plot_ly(type = 'scatter', mode = 'markers') %>%
add_trace(x = Type1$Flavanoids,y = Type1$Proline,opacity = 0.5,
marker = list(color = "#00AFBB", size = 7,line = list(color = 'lightgray',
width = .5)),name = 'Type 1') %>%
add_trace(x = Type2$Flavanoids,y = Type2$Proline,
marker = list( color = "#E7B800", size = 7,line = list(color = 'lightgray',
width = .5)), name = 'Type 2') %>%
add_trace(x = Type3$Flavanoids, y = Type3$Proline,
marker = list(color = "#FC4E07",size = 7, line = list(color = 'lightgray',
width = .5)), name = 'Type 3') %>%
layout(title = 'Scatterplot of Flavanoids & Proline',
xaxis = list(title = 'flavanoids',
zeroline = FALSE),
yaxis = list(title = 'proline'))
g8a
# Automated method, ggplot style
g8b <- wine %>%
plot_ly(x = ~Flavanoids, y = ~Proline, color = ~Type, colors = c("#00AFBB", "#E7B800", "#FC4E07"),
type = 'scatter', mode = 'markers') %>% # initialize graph in plotly, use ~ for aes mappings
layout(title = 'Scatterplot of Flavanoids & Proline',
xaxis = list(title = 'flavanoids',
zeroline = FALSE),
yaxis = list(title = 'proline'))
g8b
g9a <- plot_ly(type = 'scatter3d', mode = 'markers')
g9a <- g9a %>%
add_trace(x = Type1$Flavanoids, y = Type1$Proline, z = Type1$Alcalinity, opacity = 0.5,
marker = list( color = "#00AFBB", size = 7,
line = list(color = 'lightgray', width = .5)), name = 'Type 1') %>%
add_trace( x = Type2$Flavanoids, y = Type2$Proline, z = Type2$Alcalinity,
marker = list( color = "#E7B800", size = 7,
line = list( color = 'lightgray',width = .5)),name = 'Type 2') %>%
add_trace( x = Type3$Flavanoids, y = Type3$Proline, z = Type3$Alcalinity,
marker = list( color = "#FC4E07", size = 7,
line = list( color = 'lightgray', width = .5 )), name = 'Type 3') %>%
layout(title = 'Scatterplot of Flavanoids, Proline & Alcalinity',
scene = list(xaxis = list(title = "flavanoids"),
yaxis = list(title = "proline"),
zaxis = list(title = "alcalinity")))
g9a
g9b <- wine %>% plot_ly( opacity = 0.5, type = 'scatter3d', mode = 'markers') %>%
add_trace(x = ~Flavanoids, y = ~Proline, z = ~Alcalinity, color = ~Type,
marker = list(size = 7,line = list(width = .5))) %>%
layout(title = 'Scatterplot of Flavanoids, Proline & Alcalinity',
scene = list(xaxis = list(title = "flavanoids"),
yaxis = list(title = "proline"),
zaxis = list(title = "alcalinity")))
g9b
(From plotly examples)
# Obtain data from subset of tooth growth dataset
tg <- ddply(ToothGrowth, c("supp", "dose"), summarise, length=mean(len))
# Create plotly figure
g10 <- plot_ly(tg, x = ~dose, y = ~length, type = 'scatter', mode = 'lines',
linetype = ~supp, color = I('black')) %>%
layout(title = 'The Effect of Vitamin C on Tooth Growth in Guinea Pigs by Supplement Type',
xaxis = list(title = 'Dose in milligrams/day'),
yaxis = list (title = 'Tooth length'))
g10